/*
    kOTF Open Trace Format - a library for generating execution traces.
    Copyright 2012 Daniel K. O.

    kOTF is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kOTF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with kOTF.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <kotf/Stream.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/thread/tss.hpp>


#include <kotf/Session.hpp>
#include "EventBuffer.hpp"
#include "StreamImpl.hpp"

namespace kotf {



    namespace {
        boost::thread_specific_ptr<string> myName;
        thread_local Stream* myStream = 0;

        string getMyName()
        {
            if (!myName.get())
                myName.reset(new string("thread-"+boost::lexical_cast<string>(std::this_thread::get_id())));
            return *myName;
        }
    }



    Stream::Stream(Session& s, uint64_t i, const string& n) :
        pimpl(new StreamImpl(*this, s, i, n))
    {
    }

    Stream::~Stream()
    {
        delete pimpl;
        if (myStream == this)
            myStream = 0;
    }

    uint64_t
    Stream::getId() const
    {return pimpl->getId();}
    

    const string&
    Stream::getName() const
    {return pimpl->getName();}

    Session&
    Stream::getSession()
    {return pimpl->getSession();}    


    void
    Stream::setLimit(size_t limit)
    {pimpl->setLimit(limit);}
    
    size_t
    Stream::getLimit() const
    {return pimpl->getLimit();}
    



    bool
    Stream::isActive() const
    {return pimpl->isActive();}
    


    void
    Stream::start(uint64_t tag)
    {pimpl->start(tag);}

    void
    Stream::start(const Stream& parent, uint64_t tag)
    {pimpl->start(parent, tag);}

    void
    Stream::finish(uint64_t tag)
    {pimpl->finish(tag);}



    void
    Stream::push(const State& st, uint64_t tag)
    {pimpl->push(st, tag);}

    void
    Stream::push(const string& stn, uint64_t tag)
    {pimpl->push(stn, tag);}

    void
    Stream::pop(const State& st, uint64_t tag)
    {pimpl->pop(st, tag);}

    void
    Stream::pop(const string& stn, uint64_t tag)
    {pimpl->pop(stn, tag);}

    void
    Stream::change(const State& oldst, const State& newst, uint64_t tag)
    {pimpl->change(oldst, newst, tag);}

    void
    Stream::change(const string& oldstn, const string& newstn, uint64_t tag)
    {pimpl->change(oldstn, newstn, tag);}


    void
    Stream::update(const Counter& c, uint64_t v, uint64_t tag)
    {pimpl->update(c, v, tag);}

    void
    Stream::update(const string& cn, uint64_t v, uint64_t tag)
    {pimpl->update(cn, v, tag);}


    void
    Stream::send(const Channel& ch, uint64_t length, uint64_t tag)
    {pimpl->send(ch, length, tag);}

    void
    Stream::send(const string& chn, uint64_t length, uint64_t tag)
    {pimpl->send(chn, length, tag);}

    void
    Stream::broadcast(const Channel& ch, uint64_t length, uint64_t tag)
    {pimpl->broadcast(ch, length, tag);}
    
    void
    Stream::broadcast(const string& chn, uint64_t length, uint64_t tag)
    {pimpl->broadcast(chn, length, tag);}

    void
    Stream::recv(const Channel& ch, uint64_t length, uint64_t tag)
    {pimpl->recv(ch, length, tag);}

    void
    Stream::recv(const string& chn, uint64_t length, uint64_t tag)
    {pimpl->recv(chn, length, tag);}






    Stream&
    Stream::mine()
    {
        if (myStream)
            return *myStream;
        
        Stream& stream = Session::getDefault().getStream(getMyName());
        myStream = &stream;
        if (!stream.isActive())
            stream.start();
        return stream;
    }

    Stream&
    Stream::mine(Session& sess)
    {
        Stream& stream = sess.getStream(getMyName());
        myStream = &stream;
        if (!stream.isActive())
            stream.start();
        return stream;
    }

    void
    Stream::setName(const string& name)
    {
        myName.reset(new string(name));
        myStream = 0;
    }


}

